////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011-2012 www.iflytek.com. All Rights Reserved.
//  This software for customer relationship management system, developed by Noo team.
//  Software code and design for the team, copy rights reserved.
////////////////////////////////////////////////////////////////////////////////

package com.iflytek.ci.common.support;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Stack;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;

/**
 * <p>
 * .
 * </p>
 *
 * @author poplar.yfyang
 * @version 1.0 2012-11-18 12:15 PM
 * @since JDK 1.5
 */
public class I18nMessageSource implements InitializingBean {
	/**
	 * 默认的Locale的字符串
	 */
	private String defaultLocaleString = "zh_CN";

	/**
	 * ResourceBundle配置的Map，其中：以文件类型为key，以对应的资源文件列表为value。
	 */
	private Map bundleMap;

	/**
	 * 缓存消息国际化
	 */
	private Map messageFormats;

	/**
	 * @param defaultLocaleString the defaultLocaleString to set
	 */
	public void setDefaultLocaleString(String defaultLocaleString) {
		this.defaultLocaleString = defaultLocaleString;
	}

	/**
	 * @param bundleMap bundle字符串的Map，其中：资源文件路径为key，此资源文件所属类型（例如：error、message、tip等，这些都是自定义的）为Value。
	 */
	public void setBundleMap(Map bundleMap) {
		Iterator keyItr = bundleMap.keySet().iterator();
		this.bundleMap = Maps.newHashMapWithExpectedSize(bundleMap.size());
		while(keyItr.hasNext()) {
			String key = (String) keyItr.next();
			String type = (String) bundleMap.get(key);
			List typeList = (List) this.bundleMap.get(type);
			if(typeList == null) {
				typeList = Lists.newArrayList();
				this.bundleMap.put(type, typeList);
			}
			typeList.add(key);
		}
	}

	public I18nMessageSource() {
		if(instance == null) {
			instance = this;
		} else {
			//throw new RuntimeException("I18nMessasgeSource的instance已经实例化不能再实例化。");
		}
	}

	/**
	 * 初始化ResourceBundle等
	 */
	public void afterPropertiesSet() throws Exception {
		//1、构建默认的Locale
		defaultLocale = new Locale(defaultLocaleString);
		//2、初始化messageKeyPool，初始化10个MessageKey对象
		messageKeyPool = new Stack<MessageKey>();
		for(int i=0; i<10; i++) {
			MessageKey key = new MessageKey(null, null, null);
			key.inPool = true;
			messageKeyPool.push(key);
		}
		//3、初始化messageFormats
		messageFormats = new HashMap();//可以考虑使用EHCache进行优化
	}

	/**
	 * Message的Key对象的POOL，防止多创建对象。
	 */
	private Stack<MessageKey> messageKeyPool;

	public static class MessageKey {
		String messageType;
		String key;
		Locale locale;
		boolean inPool;

		public MessageKey(String messageType, String key, Locale locale) {
			this.setMessageKey(messageType, key, locale);
		}

		public void setMessageKey(String messageType, String key, Locale locale) {
			this.messageType = messageType;
			this.key = key;
			this.locale = locale;
		}

		public void clear() {
			this.messageType = null;
			this.key = null;
			this.locale = null;
		}

		@Override
		public int hashCode() {
			return messageType.hashCode() + key.hashCode() + locale.hashCode();
		}

		@Override
		public boolean equals(Object obj) {
			MessageKey other = (MessageKey) obj;
			return locale.equals(other.locale) && messageType.equals(other.messageType) && key.equals(other.key);
		}
	}

	public String findMessage(String messageType, String key) {
		return this.findMessage(messageType, key, nullArgs, defaultLocale);
	}

	public String findMessage(String messageType, String key, Object[] args) {
		return this.findMessage(messageType, key, args, defaultLocale);
	}

	/**
	 * 查找国际化消息
	 *
	 * @param messageType 资源文件所属类型（例如：error、message、tip等，这些都是自定义的）
	 * @param key
	 * @param args
	 * @param locale
	 * @return
	 */
	public String findMessage(String messageType, String key, Object[] args, Locale locale) {
		MessageKey messageKey = getMessageKey(messageType, key, locale);
		MessageFormat mf = null;
		try{
			mf = (MessageFormat) messageFormats.get(messageKey);
			if(mf == null) {
				//reload具体的Message
				List typeList = (List) bundleMap.get(messageType);
				if(typeList != null) {
					for (Object aTypeList : typeList) {
						try {
							ResourceBundle rb = ResourceBundle.getBundle((String) aTypeList, locale);
							String messageDef = rb.getString(key);
							if (messageDef != null) {
								mf = buildMessageFormat(messageType, key,
										locale, messageDef);
							}
						} catch (MissingResourceException e) {
							logger.error(e.getMessage());
						}
					}
					if(mf == null) {
						logger.error("在[" + messageType + "]中对应的" +typeList+ "的" + locale +"文件中未找到[" + key + "]的消息定义。");
					}
				} else {
					logger.error("未找到[" + messageType + "]的定义。");
				}
			}
		} finally {
			releaseMessageKey(messageKey);
		}
		if(mf != null)
			return mf.format(args);
		return null;
	}

	/**
	 * 创建MessageFormat对象，并且将对象放到缓存中。
	 *
	 * @param messageType
	 * @param key
	 * @param locale
	 * @param messageDef
	 * @return
	 */
	private MessageFormat buildMessageFormat(String messageType, String key,
											 Locale locale, String messageDef) {
		MessageFormat mf;
		mf = new MessageFormat(messageDef);
		MessageKey mk = new MessageKey(messageType, key, locale);
		messageFormats.put(mk, mf);
		return mf;
	}

	/**
	 * 获得MessageKey，首先从Pool中取，如果现在Pool为空时系统自动创建一个新MessageKey对象。
	 *
	 * @param messageType
	 * @param key
	 * @param locale
	 * @return
	 */
	private MessageKey getMessageKey(String messageType, String key, Locale locale) {
		MessageKey messageKey;
		if(!messageKeyPool.isEmpty()) {
			messageKey = messageKeyPool.pop();
			messageKey.setMessageKey(messageType, key, locale);
		} else {
			logger.warn("messageKeyPool已被耗尽。");
			messageKey = new MessageKey(messageType, key, locale);
			messageKey.inPool = false;
		}
		return messageKey;
	}

	/**
	 * 释放MessageKey
	 *
	 * @param messageKey
	 */
	private void releaseMessageKey(MessageKey messageKey) {
		if(messageKey != null && messageKey.inPool) {
			messageKey.clear();
			messageKeyPool.push(messageKey);
		}
	}

	/**
	 * 空参数
	 */
	private static final Object[] nullArgs = new Object[0];

	/**
	 * 默认的Locale对象
	 */
	private static Locale defaultLocale;

	private static Logger logger = LoggerFactory.getLogger(I18nMessageSource.class);

	public static String findText(String messageType, String key) {
		return instance.findMessage(messageType, key, nullArgs, defaultLocale);
	}

	public static String findText(String messageType, String key, Object[] args) {
		return instance.findMessage(messageType, key, args, defaultLocale);
	}

	public static String findText(String messageType, String key, Locale locale) {
		return instance.findMessage(messageType, key, nullArgs, locale);
	}

	public static String findText(String messageType, String key, Object[] args, Locale locale) {
		return instance.findMessage(messageType, key, args, locale);
	}

	private static I18nMessageSource instance;

	/**
	 * 得到I18nMessasgeSource的实例
	 */
	public static I18nMessageSource getInstance() {
		return instance;
	}
}
